#include <assert.h>
#include <getopt.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "server.h"

int verbose;
const char* program_name = "server";

static const struct option long_options[] = {
    { "address", 1, NULL, 'a' },
    { "help", 0, NULL, 'h' },
    { "module-dir", 1, NULL, 'm' },
    { "port", 1, NULL, 'p' },
    { "verbose", 0, NULL, 'v' },
};

static const char* short_options ="a:hm:p:v";
static const char* const usage_template =
    "Usage: %s [ options ]\n"
    " -a, --address ADDR Bind to local address (by default, bind\n"
    " to all local addresses).\n"
    " -h, --help Print this information.\n"
    " -m, --module-dir DIR Load modules from specified directory\n"
    " (by default, use executable directory).\n"
    " -p, --port PORT Bind to specified port.\n"
    " -v, --verbose Print verbose messages.\n";

static void print_usage(int is_error){
    fprintf(is_error?stderr:stdout,usage_template,program_name);
    exit(is_error?1:0);
}
int main(int argc,char** argv){

    struct in_addr local_address;
    uint16_t port;
    int next_option;
    program_name = argv[0];

    local_address.s_addr = INADDR_ANY;
    port = 0;
    /* Don’t print verbose messages. */
    verbose = 0;
    char* module_dir = get_self_executable_directory();
    /* Parse options. */
    do {
        next_option =
        getopt_long (argc, argv, short_options, long_options, NULL);
        switch (next_option) {
            case 'a':
                /* User specified -a or --address. */
            {
                struct hostent* local_host_name;
                /* Look up the hostname the user specified. */
                local_host_name = gethostbyname (optarg);
                if (local_host_name == NULL || local_host_name->h_length == 0)
                    /* Could not resolve the name. */
                    error (optarg, "invalid host name");
                else
                    /* Hostname is OK, so use it. */
                    local_address.s_addr =
                    *((int*) (local_host_name->h_addr_list[0]));
            }
            break;
            case 'h':
                /* User specified -h or --help. */
                print_usage (0);
            case 'm':
            /* User specified -m or --module-dir. */
            {
                struct stat dir_info;
                /* Check that it exists. */
                if (access (optarg, F_OK) != 0)
                    error (optarg, "module directory does not exist");
                /* Check that it is accessible. */
                if (access (optarg, R_OK | X_OK) != 0)
                    error (optarg, "module directory is not accessible");
                /* Make sure that it is a directory. */
                if (stat (optarg, &dir_info) != 0 || !S_ISDIR (dir_info.st_mode))
                    error (optarg, "not a directory");
                /* It looks OK, so use it. */
                module_dir = strdup (optarg);
            }
            break;
            case 'p':
            /* User specified -p or --port. */
            {
                long value;
                char* end;
                value = strtol (optarg, &end, 10);
                if (*end != 0)
                /* The user specified nondigits in the port number. */
                print_usage (1);
                /* The port number needs to be converted to network (big endian)
                byte order. */
                port = (uint16_t) htons (value);
            }
            break;
            case 'v':
                /* User specified -v or --verbose. */
                verbose = 1;
                break;
            case '?':
                /* User specified an unrecognized option. */
                print_usage (1);
                case -1:
                /* Done with options. */
                break;
            default:
                abort ();
                
        }

    }while (next_option != -1);
    if (optind != argc)
        print_usage (1);
    if (verbose)
        printf ("modules will be loaded from %s\n", module_dir);


    server_run (local_address, port);
}